//
// Unihan Input Method
//
// Copyright © 2002-2007 Sun Wah Linux Ltd.
//
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
// USA
//
// $Id: cands_factory.c 757 2007-05-10 08:19:31Z roger $
//

#include <string.h>
#include <stdio.h>
#include <unistd.h>

#include "cands_factory.h"
#include "table.h"

static MultiCandPos *CF_MultiCandPos_dup(MultiCandPos *multiCandPos);

void
CF_append_InputCell(InputCell **ic, char *cell)
{
	InputCell *endCell;

	endCell = *ic;
	if (!endCell) {
		endCell = *ic = (InputCell *)malloc(sizeof(InputCell));
		endCell->cell = strdup(cell);
		endCell->next = NULL;
	}
	else {
		while (endCell->next)
			endCell = endCell->next;
		endCell->next = (InputCell *)malloc(sizeof(InputCell));
		endCell = endCell->next;
		endCell->cell = strdup(cell);
		endCell->next = NULL;
	}
}

void
CF_free_InputCell(InputCell *inputCell)
{
	InputCell *ic;
	InputCell *ic_next;

	if (ic) {
		ic = inputCell;
		ic_next = ic->next;
	}
	else
		return;

	while(ic) {
		free(ic->cell);
		ic = ic_next;
		if (ic_next)
			ic_next = ic_next->next;
	}
}

void
CF_throw_a_key(CandFactory *candFactory)
{
	MultiCandPos *mcp = candFactory->multiCandPos;
	InputCell *ic_end = NULL;
	InputCell *ic_before = NULL;
	char *cell = NULL;

	while (mcp) {
		ic_before = mcp->inputCell;
		if (!ic_before) {
			mcp = mcp->next;
			continue;
		}

		ic_end = ic_before->next;
		if (!ic_end) {
			cell = ic_before->cell;
			if (cell[1] == 0) {
				free(cell);
				free(ic_before);
				mcp->inputCell = NULL;
			}
			else {
				cell[strlen(cell-1)] = 0;
				CF_intergrate_cells_to_preedit(mcp);
			}
			mcp = mcp->next;
			continue;
		}

		while (ic_end->next) {
			ic_end = ic_end->next;
			ic_before = ic_before->next;
		}

		cell = ic_end->cell;
		if (cell[1] == 0) {
			free(cell);
			cell = NULL;
			free(ic_end);
			ic_before->next = NULL;
			CF_intergrate_cells_to_preedit(mcp);
		}
		else {
			cell[strlen(cell)-1] = 0;
			CF_intergrate_cells_to_preedit(mcp);
		}
		mcp = mcp->next;
	}
}

void
CF_all_throw_a_InputCell(CandFactory *candFactory)
{
	MultiCandPos *mcp = candFactory->multiCandPos;

	while (mcp) {
		InputCell *ic_before = mcp->inputCell;
		InputCell *ic_end;

		if (!ic_before) {
			mcp = mcp->next;
			continue;
		}

		ic_end = ic_before->next;
		if (!ic_end) {
			free(ic_before->cell);
			free(ic_before);
			mcp->inputCell = NULL;
			continue;
		}

		while (ic_end->next) {
			ic_before = ic_before->next;
			ic_end = ic_end->next;
		}

		free(ic_end->cell);
		free(ic_end);
		ic_before->next = NULL;
		mcp = mcp->next;
	}
}

MultiCandPos *
CF_append_MultiCandPos(MultiCandPos *mcp)
{
	return NULL;
}

void
CF_free_MultiCandPos(MultiCandPos *multiCandPos)
{
	if (!multiCandPos)
		return;
	CF_free_InputCell(multiCandPos->inputCell);
	free(multiCandPos);
}

int
CF_double_MultiCandPos(CandFactory *candFactory)
{
	int num = 0;
	MultiCandPos *mcp = candFactory->multiCandPos;
	MultiCandPos *mcp_new = NULL;
	MultiCandPos *mcp_head = NULL;

	if (!mcp)
		return 0;

	mcp_head = mcp_new = CF_MultiCandPos_dup(mcp);
	num++;

	while(mcp->next) {
		mcp_new->next = CF_MultiCandPos_dup(mcp->next);
		mcp_new = mcp_new->next;
		num++;
		mcp = mcp->next;
	}

	mcp_new->next = NULL;
	mcp->next = mcp_head;
	candFactory->numMultiCandPos = num * 2;

	return num * 2; 
}

int
CF_half_MultiCandPos(CandFactory *candFactory)
{
	int i;
	MultiCandPos *mcp = candFactory->multiCandPos;
	MultiCandPos *mcp_end = NULL;

	if (!mcp)
		return;

	for (i=0; i<candFactory->numMultiCandPos; i++) {
		MultiCandPos *mcp_next;

		if (i < candFactory->numMultiCandPos/2) {
			if (i == candFactory->numMultiCandPos/2 - 1)
				mcp_end = mcp;
			mcp = mcp->next;
		}
		else {
			mcp_next = mcp->next;
			CF_free_MultiCandPos(mcp);
			mcp = mcp_next;
		}
	}

	if (mcp_end) {
		mcp_end->next = NULL;
	}
	candFactory->numMultiCandPos /= 2;
	return candFactory->numMultiCandPos;
}

void
CF_display_tree(CandFactory *candFactory)
{
	MultiCandPos *mcp = candFactory->multiCandPos;
	InputCell *ic = NULL;
	FILE *pf = fopen("/root/debug.input", "a");
	if (!pf)
		return;

	if (candFactory == NULL) {
		fprintf(pf, "cand factory NULL ...\n");
		fclose(pf);
		return;
	}

	fprintf(pf, "total cands number : %d\n", candFactory->numTotalCands);
	if (candFactory->word)
		fprintf(pf, "find word : %s...\n", candFactory->word);
	else
		fprintf(pf, "no word finded ...\n");

	if (candFactory->keys[0] != 0)
		fprintf(pf, "find keys : %s ...\n", candFactory->keys);
	else
		fprintf(pf, "no keys finded ...\n");

	if (mcp) {
		while (mcp) {
			fprintf(pf, "MultiCandPos numCands : %d\n", mcp->numCands);
			if (mcp->preedit)
				fprintf(pf, "MultiCandPos Preedit : %s\n", mcp->preedit);
			else
				fprintf(pf, "MultiCandPos Preedit NULL ... \n");
			ic = mcp->inputCell;
			if (ic)
				while (ic) {
					fprintf(pf, "MultiCandPos InputCell : %s\n", ic->cell);
					ic = ic->next;
				}
			else
				fprintf(pf, "MultiCandPos InputCell NULL ...\n");
			mcp = mcp->next;
		}
	}
	else
		fprintf(pf, "no MultiCandPos finded ...\n");
	fprintf(pf, "\n\n");
	fclose(pf);
}

static MultiCandPos *
CF_MultiCandPos_dup(MultiCandPos *multiCandPos)
{
	MultiCandPos *mcp_new = malloc(sizeof(MultiCandPos));
	InputCell *ic = multiCandPos->inputCell;

	memcpy(mcp_new, multiCandPos, sizeof(MultiCandPos));
	mcp_new->inputCell = NULL;
	mcp_new->next = NULL;
	while (ic) {
		CF_append_InputCell(&(mcp_new->inputCell), ic->cell);
		ic = ic->next;
	}
	return mcp_new;
}

void
CF_erase_keys(CandFactory *candFactory)
{
	MultiCandPos *multiCandPos = candFactory->multiCandPos;

	if (candFactory->keys[0] == 0)
		return;

	while (multiCandPos) {
		CF_append_InputCell(&(multiCandPos->inputCell),
				candFactory->keys);
		//strcat(multiCandPos->preedit, candFactory->keys);
		multiCandPos = multiCandPos->next;
	}

	candFactory->keys[0] = 0;

	return;
}

void
CF_erase_keys_with_cell(CandFactory *candFactory, char *now, char *other)
{
	MultiCandPos *multiCandPos = candFactory->multiCandPos;
	int num = 0;
	int i = 0;

	if (now != candFactory->keys) {
		char buf[CF_PREEDIT_MAX_LEN];
		memset(buf, 0, sizeof(buf));
	
		strncpy(buf, candFactory->keys, now - candFactory->keys);
		while (multiCandPos) {
			CF_append_InputCell(&(multiCandPos->inputCell),
					buf);
			multiCandPos = multiCandPos->next;
		}
	}

	num = CF_double_MultiCandPos(candFactory);
	if (!num)
		return;

	multiCandPos = candFactory->multiCandPos;
	while(multiCandPos) {
		if (i < num/2)
			CF_append_InputCell(&(multiCandPos->inputCell),
					now);
		else
			CF_append_InputCell(&(multiCandPos->inputCell),
					other);

		CF_intergrate_cells_to_preedit(multiCandPos);

		i++;
		multiCandPos = multiCandPos->next;
	}

	candFactory->keys[0] = 0;
}

void
CF_set_the_last_InputCell_to_keys(CandFactory *candFactory)
{
	MultiCandPos *mcp = candFactory->multiCandPos;
	InputCell *ic = mcp->inputCell;

	if (!ic)
		return;

	while (ic->next)
		ic = ic->next;

	strcpy(candFactory->keys, ic->cell);
}

void
CF_clear_CandFactory(CandFactory *candFactory)
{
	MultiCandPos *mcp;
	MultiCandPos *mcp_next;

	if (candFactory->freqCandList) {
		free(candFactory->freqCandList);
		candFactory->freqCandList = NULL;
	}

	if (candFactory->multiCandPos) {
		mcp = candFactory->multiCandPos;
		mcp_next = mcp->next;
	}
	else
		return;

	while (mcp) {
		CF_free_MultiCandPos(mcp);
		mcp = mcp_next;
		if (mcp_next)
			mcp_next = mcp_next->next;
	}
	candFactory->multiCandPos = NULL;
}

int
CF_get_cand_idx_by_id(CandFactory *candFactory, int id)
{
	int idx = 0;
	MultiCandPos *mcp = candFactory->multiCandPos;
	int numTotalCands = 0;
	int offset = 0;

	if (!mcp)
		return 0;

	while (mcp) {
		numTotalCands += mcp->numCands;
		if (numTotalCands < id)
			mcp = mcp->next;
		else {
			offset = id - (numTotalCands - mcp->numCands);
			break;
		}
	}

	idx = mcp->lowIdx + offset;

	return idx;
}

void
CF_intergrate_cells_to_preedit(MultiCandPos *multiCandPos)
{
	InputCell *ic = multiCandPos->inputCell;

	memset(multiCandPos->preedit, 0, sizeof(multiCandPos->preedit));

	while(ic) {
		strcat(multiCandPos->preedit, ic->cell);
		ic = ic->next;
	}
}

// vi:ts=4:nowrap:cin:expandtab
